home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / world.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  36.4 KB  |  1,658 lines  |  [TEXT/KAHL]

  1. /* Worlds and areas in Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11.  
  12. /* The main world structure. */
  13.  
  14. World world;
  15.  
  16. /* The current area of the world. */
  17.  
  18. Area area;
  19.  
  20. /* This is the number of terrain types that can fill a cell. */
  21.  
  22. int numcelltypes = 0;
  23.  
  24. /* This is the number of terrain types that can be border terrain. */
  25.  
  26. int numbordtypes = 0;
  27.  
  28. /* This is the number of types that can be connections. */
  29.  
  30. int numconntypes = 0;
  31.  
  32. /* This is the number of types that can be coatings. */
  33.  
  34. int numcoattypes = 0;
  35.  
  36. /* (Features could also be used to implement the region 
  37.    labeling scheme now used only in the machine player) */
  38.  
  39. Feature *featurelist = NULL;
  40.  
  41. Feature *last_feature = NULL;
  42.  
  43. /* Feature id 0 means no geographical feature defined. */
  44.  
  45. int nextfid = 1;
  46.  
  47. int minelev;
  48. int maxelev;
  49.  
  50. int mintemp;
  51. int maxtemp;
  52.  
  53. int any_temp_variation = FALSE;
  54.  
  55. int any_temp_variation_in_layer = FALSE;
  56.  
  57. int minwindforce;
  58. int maxwindforce;
  59.  
  60. int any_wind_variation = FALSE;
  61.  
  62. int any_wind_variation_in_layer = FALSE;
  63.  
  64. int minclouds;
  65. int maxclouds;
  66.  
  67. int any_clouds = FALSE;
  68.  
  69. /* This is true if it is ever possible to have quantities of material
  70.    in cells. */
  71.  
  72. int any_materials_in_terrain = FALSE;
  73.  
  74. static Feature *tmpfeature;
  75.  
  76. static int tmpint;
  77.  
  78. static int tmpint2, tmpint3;
  79.  
  80. /* Clean out all the world and area data. */
  81.  
  82. void
  83. init_world()
  84. {
  85.     memset(&world, 0, sizeof(World));
  86.     /* These default values effectively disable day and year effects. */
  87.     world.daylength = 1;
  88.     world.yearlength = 1;
  89.     /* Init the current (default) area. */
  90.     memset(&area, 0, sizeof(Area));
  91.     /* Note especially that area width and height dimensions are now zero. */
  92. }
  93.  
  94. int
  95. set_world_circumference(circum, warn)
  96. int circum, warn;
  97. {
  98.     /* All world circumferences are valid, no checks necessary. */
  99.     world.circumference = circum;
  100.     area.xwrap = (world.circumference == area.width);
  101.     return TRUE;
  102. }
  103.  
  104. int
  105. set_area_shape(width, height, warn)
  106. int width, height, warn;
  107. {
  108.     if (!valid_area_shape(width, height, warn))
  109.       return FALSE;
  110.     area.width = width;  area.height = height;
  111.     area.maxdim = max(area.width, area.height);
  112.     area.xwrap = (world.circumference == area.width);
  113.     return TRUE;
  114. }
  115.  
  116. int
  117. valid_area_shape(width, height, warn)    
  118. int width, height, warn;
  119. {
  120.     if (width < MINWIDTH || height < MINHEIGHT) {
  121.     if (warn)
  122.       init_warning("area is %dx%d, too small", width, height);
  123.         return FALSE;
  124.     }
  125.     if (width != world.circumference && width * 2 < height) {
  126.     if (warn)
  127.       init_warning("hexagon area is %dx%d, impossible dimensions",
  128.                width, height);
  129.         return FALSE;
  130.     }
  131.     return TRUE;
  132. }
  133.  
  134. void
  135. check_area_shape()
  136. {
  137.     if (area.width == 0 || area.height == 0)
  138.       run_error("0x0 area");
  139.     if (!valid_area_shape(area.width, area.height, TRUE))
  140.       run_error("sorry, this is a fatal error here");
  141. }
  142.  
  143. /* Calculate globals that we can use later to decide if particular
  144.    classes of calculations need to be done, such as weather changes. */
  145.  
  146. void
  147. calculate_world_globals()
  148. {
  149.     int t, m;
  150.  
  151.     /* This is a last chance to set a default world size.
  152.        Will usually be set already, by players or by module. */
  153.     if (area.width <= 0 && area.height <= 0)
  154.       set_area_shape(DEFAULTWIDTH, DEFAULTHEIGHT, 0);
  155.     minelev = t_elev_min(0);
  156.     maxelev = t_elev_max(0);
  157.     mintemp = t_temp_min(0);
  158.     maxtemp = t_temp_max(0);
  159.     minwindforce = t_wind_force_min(0);
  160.     maxwindforce = t_wind_force_max(0);
  161.     minclouds = t_clouds_min(0);
  162.     maxclouds = t_clouds_max(0);
  163.     for_all_terrain_types(t) {
  164.     if (t_elev_min(t) < minelev) minelev = t_elev_min(t);
  165.     if (t_elev_max(t) > maxelev) maxelev = t_elev_max(t);
  166.     if (t_temp_min(t) < mintemp) mintemp = t_temp_min(t);
  167.     if (t_temp_max(t) > maxtemp) maxtemp = t_temp_max(t);
  168.     if (t_wind_force_min(t) < maxwindforce)
  169.       minwindforce = t_wind_force_min(t);
  170.     if (t_wind_force_max(t) > maxwindforce)
  171.       maxwindforce = t_wind_force_max(t);
  172.     if (t_clouds_min(t) < minclouds)
  173.       minclouds = t_clouds_min(t);
  174.     if (t_clouds_max(t) > maxclouds)
  175.       maxclouds = t_clouds_max(t);    
  176.     /* Decide if materials can ever be accumulated in cells. */
  177.     for_all_material_types(m) {
  178.         if (tm_storage_x(t, m) > 0) any_materials_in_terrain = TRUE;
  179.     }
  180.     }
  181.     if (mintemp != maxtemp) any_temp_variation = TRUE;
  182.     if (minwindforce != maxwindforce) any_wind_variation = TRUE;
  183.     /* (should figure out what this is supposed to mean really) */
  184.     if (minwindforce != maxwindforce) any_wind_variation_in_layer = TRUE;
  185.     if (minclouds != maxclouds) any_clouds = TRUE;
  186. }
  187.  
  188. void
  189. count_terrain_subtypes()
  190. {
  191.     int t;
  192.  
  193.     numcelltypes = numbordtypes = numconntypes = numcoattypes = 0;
  194.     for_all_terrain_types(t) {
  195.     switch (t_subtype(t)) {
  196.       case cellsubtype:
  197.         ++numcelltypes;
  198.         break;
  199.       case bordersubtype:
  200.         ++numbordtypes;
  201.         break;
  202.       case connectionsubtype:
  203.         ++numconntypes;
  204.         break;
  205.       case coatingsubtype:
  206.         ++numcoattypes;
  207.         break;
  208.     }
  209.     }
  210. }
  211.  
  212. /* Make space for an area's terrain, and for the unit cache. */
  213.  
  214. /* This can be postponed until it is actually needed. */
  215.  
  216. void
  217. allocate_area_terrain()
  218. {
  219.     check_area_shape();
  220.     /* Get rid of old stuff maybe. (is this desirable?) */
  221.     if (area.terrain != NULL) {
  222.     free((char *) area.terrain);
  223.     free((char *) area.units);
  224.     }
  225.     /* Allocate the basic terrain layer. */
  226.     /* It doesn't matter what ttype 0 is, we're guaranteed that it
  227.        will be defined eventually. */
  228.     area.terrain = malloc_area_layer(char);
  229.     /* Allocate and null out the unit cache. */
  230.     area.units = malloc_area_layer(Unit *);
  231. }
  232.  
  233. /* Set up the auxiliary terrain layer of the area. */
  234.  
  235. void
  236. allocate_area_aux_terrain(t)
  237. int t;
  238. {
  239.     if (!any_aux_terrain_defined()) {
  240.     area.auxterrain = (char **) xmalloc(numttypes * sizeof(char *));
  241.     }
  242.     if (!aux_terrain_defined(t)) {
  243.     area.auxterrain[t] = malloc_area_layer(char);
  244.     }
  245. }
  246.  
  247. /* Allocate some number of scratch layers.  These are used as temporaries
  248.    in calculations, etc. */
  249.  
  250. void
  251. allocate_area_scratch(n)
  252. int n;
  253. {
  254.     check_area_shape();
  255.     if (n >= 1 && !area.tmp1) {
  256.     area.tmp1 = malloc_area_layer(short);
  257.     }
  258.     if (n >= 2 && !area.tmp2) {
  259.     area.tmp2 = malloc_area_layer(short);
  260.     }
  261.     if (n >= 3 && !area.tmp3) {
  262.     area.tmp3 = malloc_area_layer(short);
  263.     }
  264. }
  265.  
  266. /* Should have something to free scratch layers up also maybe. */
  267.  
  268. /* Allocate and init the elevation layer. */
  269.  
  270. void
  271. allocate_area_elevations()
  272. {
  273.     if (!elevations_defined()) {
  274.     check_area_shape();
  275.     area.elevations = malloc_area_layer(short);
  276.     }
  277. }
  278.  
  279. /* Allocate and init the temperature layer. */
  280.  
  281. void
  282. allocate_area_temperatures()
  283. {
  284.     if (!temperatures_defined()) {
  285.     check_area_shape();
  286.     area.temperature = malloc_area_layer(short);
  287.     }
  288.     /* We'll need one scratch layer too. */
  289.     allocate_area_scratch(1);
  290. }
  291.  
  292. /* Allocate a layer indicating the side of the people living in each cell. */
  293.  
  294. void
  295. allocate_area_people_sides()
  296. {
  297.     int x, y;
  298.  
  299.     if (!people_sides_defined()) {
  300.     check_area_shape();
  301.     area.peopleside = malloc_area_layer(char);
  302.     for_all_cells(x, y) {
  303.         set_people_side_at(x, y, NOBODY);
  304.     }
  305.     }
  306. }
  307.  
  308. /* Set up a cell material layer of the area. */
  309.  
  310. void
  311. allocate_area_material(m)
  312. int m;
  313. {
  314.     check_area_shape();
  315.     if (!any_cell_materials_defined()) {
  316.     area.materials = (short **) xmalloc(nummtypes * sizeof(short *));
  317.     }
  318.     if (!cell_material_defined(m)) {
  319.     area.materials[m] = malloc_area_layer(short);
  320.     }
  321. }
  322.  
  323. void
  324. allocate_area_clouds()
  325. {
  326.     if (!clouds_defined()) {
  327.     check_area_shape();
  328.     area.clouds = malloc_area_layer(short);
  329.     }
  330. }
  331.  
  332. void
  333. allocate_area_cloud_altitudes()
  334. {
  335.     allocate_area_cloud_bottoms();
  336.     allocate_area_cloud_heights();
  337. }
  338.  
  339. void
  340. allocate_area_cloud_bottoms()
  341. {
  342.     if (!cloud_bottoms_defined()) {
  343.     check_area_shape();
  344.     area.cloudbottoms = malloc_area_layer(short);
  345.     }
  346. }
  347.  
  348. void
  349. allocate_area_cloud_heights()
  350. {
  351.     if (!cloud_heights_defined()) {
  352.     check_area_shape();
  353.     area.cloudheights = malloc_area_layer(short);
  354.     }
  355. }
  356.  
  357. void
  358. allocate_area_winds()
  359. {
  360.     if (!winds_defined()) {
  361.     check_area_shape();
  362.     area.winds = malloc_area_layer(short);
  363.     }
  364. }
  365.  
  366. int
  367. fn_terrain_at(x, y)
  368. int x, y;
  369. {
  370.     return terrain_at(x, y);
  371. }
  372.  
  373. int
  374. fn_aux_terrain_at(x, y)
  375. int x, y;
  376. {
  377.     return aux_terrain_at(x, y, tmpttype);
  378. }
  379.  
  380. int
  381. fn_feature_at(x, y)
  382. int x, y;
  383. {
  384.     return raw_feature_at(x, y);
  385. }
  386.  
  387. int
  388. fn_elevation_at(x, y)
  389. int x, y;
  390. {
  391.     return elev_at(x, y);
  392. }
  393.  
  394. int
  395. fn_people_side_at(x, y)
  396. int x, y;
  397. {
  398.     return people_side_at(x, y);
  399. }
  400.  
  401. int
  402. fn_material_at(x, y)
  403. int x, y;
  404. {
  405.     return material_at(x, y, tmpmtype);
  406. }
  407.  
  408. int
  409. fn_temperature_at(x, y)
  410. int x, y;
  411. {
  412.     return temperature_at(x, y);
  413. }
  414.  
  415. int
  416. fn_raw_cloud_at(x, y)
  417. int x, y;
  418. {
  419.     return raw_cloud_at(x, y);
  420. }
  421.  
  422. int
  423. fn_raw_cloud_bottom_at(x, y)
  424. int x, y;
  425. {
  426.     return raw_cloud_bottom_at(x, y);
  427. }
  428.  
  429. int
  430. fn_raw_cloud_height_at(x, y)
  431. int x, y;
  432. {
  433.     return raw_cloud_height_at(x, y);
  434. }
  435.  
  436. int
  437. fn_raw_wind_at(x, y)
  438. int x, y;
  439. {
  440.     return raw_wind_at(x, y);
  441. }
  442.  
  443. void
  444. fn_set_terrain_at(x, y, val)
  445. int x, y, val;
  446. {
  447.     extern warnbadterrain, numbadterrain;
  448.  
  449.     /* It's important not to put bad values into the terrain layer. */
  450.     if (!is_terrain_type(val)) {
  451.         /* Only warn the first few times, just count thereafter. */
  452.         if (warnbadterrain && numbadterrain < 10) {
  453.         read_warning("Unknown terrain type (%d) at %d,%d; substituting %s",
  454.              val, x, y, t_type_name(0));
  455.     }
  456.     val = 0;
  457.     ++numbadterrain;
  458.     }
  459.     set_terrain_at(x, y, val);
  460. }
  461.  
  462. void
  463. fn_set_aux_terrain_at(x, y, val)
  464. int x, y, val;
  465. {
  466.     /* Filter anything but the basic six bits. */
  467.     val &= 0x3f;
  468.     set_aux_terrain_at(x, y, tmpttype, val);
  469. }
  470.  
  471. void
  472. fn_set_people_side_at(x, y, val)
  473. int x, y, val;
  474. {
  475.     set_people_side_at(x, y, val);
  476. }
  477.  
  478. void
  479. fn_set_raw_feature_at(x, y, val)
  480. int x, y, val;
  481. {
  482.     set_raw_feature_at(x, y, val);
  483. }
  484.  
  485. void
  486. fn_set_elevation_at(x, y, val)
  487. int x, y, val;
  488. {
  489.     set_elev_at(x, y, val);
  490. }
  491.  
  492. void
  493. fn_set_material_at(x, y, val)
  494. int x, y, val;
  495. {
  496.     set_material_at(x, y, tmpmtype, val);
  497. }
  498.  
  499. void
  500. fn_set_temperature_at(x, y, val)
  501. int x, y, val;
  502. {
  503.     set_temperature_at(x, y, val);
  504. }
  505.  
  506. void
  507. fn_set_raw_wind_at(x, y, val)
  508. int x, y, val;
  509. {
  510.     set_raw_wind_at(x, y, val);
  511. }
  512.  
  513. void
  514. fn_set_raw_cloud_at(x, y, val)
  515. int x, y, val;
  516. {
  517.     set_raw_cloud_at(x, y, val);
  518. }
  519.  
  520. void
  521. fn_set_raw_cloud_bottom_at(x, y, val)
  522. int x, y, val;
  523. {
  524.     set_raw_cloud_bottom_at(x, y, val);
  525. }
  526.  
  527. void
  528. fn_set_raw_cloud_height_at(x, y, val)
  529. int x, y, val;
  530. {
  531.     set_raw_cloud_height_at(x, y, val);
  532. }
  533.  
  534. /* Generalized area search routine.  It starts in the immediately adjacent
  535.    cells and expands outwards.  The basic structure is to examine successive
  536.    "rings" out to the max distance; within each ring, we must scan each of
  537.    six faces (picking a random one to start with) by iterating along that
  538.    face, in a direction 120 degrees from the direction out to one corner of
  539.    the face.  Draw a picture if you want to understand it... */
  540.  
  541. /* Incr is normally one.  It is set to area_size to search on areas
  542.    instead of cells. */
  543.  
  544. /* Note that points far outside the map may be generated, but the predicate
  545.    will not be called on them.  It may be applied to the same point several
  546.    times, however, if the distance is enough to wrap around the area. */
  547.  
  548. /* This needs to be changed to understand different world shapes. */
  549.  
  550. int
  551. search_around(x0, y0, maxdist, pred, rxp, ryp, incr)
  552. int x0, y0, maxdist, (*pred) PROTO ((int, int)), *rxp, *ryp, incr;
  553. {
  554.     int clockwise, dist, dd, d, dir, x1, y1, i, dir2, x, y, xw;
  555.  
  556.     maxdist = max(min(maxdist, area.width), min(maxdist, area.height));
  557.     clockwise = (flip_coin() ? 1 : -1);
  558.     for (dist = 1; dist <= maxdist; dist += incr) {
  559.     dd = random_dir();
  560.     for_all_directions(d) {
  561.         dir = (d + dd) % NUMDIRS;
  562.         x1 = x0 + dist * dirx[dir];
  563.         y1 = y0 + dist * diry[dir];
  564.         for (i = 0; i < dist; ++i) {
  565.         dir2 = opposite_dir(dir + clockwise);
  566.         x = x1 + i * dirx[dir2] * incr;
  567.         y = y1 + i * diry[dir2] * incr;
  568.         xw = wrapx(x);
  569.         if (inside_area(x, y) && (*pred)(xw, y)) {
  570.             *rxp = xw;  *ryp = y;
  571.             return TRUE;
  572.         }
  573.         }
  574.     }
  575.     }
  576.     return FALSE;
  577. }
  578.  
  579. int
  580. search_and_apply(x0, y0, maxdist, pred, rxp, ryp, incr, fn, num)
  581. int x0, y0, maxdist, *rxp, *ryp, incr;
  582. int (*pred) PROTO ((int, int));
  583. void (*fn) PROTO ((int, int));
  584. long num;
  585. {
  586.     int clockwise, dist, x0w, dd, d, dir, x1, y1, i, dir2, x, y, xw;
  587.  
  588.     maxdist = max(min(maxdist, area.width), min(maxdist, area.height));
  589.     clockwise = (flip_coin() ? 1 : -1);
  590.     if (maxdist >= 0) {
  591.     x0w = wrapx(x0);
  592.     if (inside_area(x0w, y0) && (*pred)(x0w, y0)) {
  593.         *rxp = x0w;  *ryp = y0;
  594.         (*fn)(x0w, y0);
  595.         if (--num <= 0)
  596.           return TRUE;
  597.     }
  598.     }
  599.     for (dist = 1; dist <= maxdist; dist += incr) {
  600.     dd = random_dir();
  601.     for_all_directions(d) {
  602.         dir = (d + dd) % NUMDIRS;
  603.         x1 = x0 + dist * dirx[dir];
  604.         y1 = y0 + dist * diry[dir];
  605.         for (i = 0; i < dist; ++i) {
  606.         dir2 = opposite_dir(dir + clockwise);
  607.         x = x1 + i * dirx[dir2] * incr;
  608.         y = y1 + i * diry[dir2] * incr;
  609.         if (between(0, y, area.height-1)) {
  610.             xw = wrapx(x);
  611.             if (inside_area(x, y) && (*pred)(xw, y)) {
  612.             *rxp = xw;  *ryp = y;
  613.             (*fn)(xw, y);
  614.             if (--num <= 0)
  615.               return TRUE;
  616.             }
  617.         }
  618.         }
  619.     }
  620.     }
  621.     return FALSE;
  622. }
  623.  
  624. /* Apply a function to every cell within the given radius, being careful (for
  625.    both safety and efficiency reasons) not to go past edges.  Note that the
  626.    distance is inclusive, and that distance of 0 means x0,y0 only.  Also,
  627.    if the distance is greater than either map dimension, this routine still
  628.    operates on a correct intersection with the area.  */
  629.  
  630. /* This routine should be avoided in time-critical code. */
  631.  
  632. void
  633. apply_to_area(x0, y0, dist, fn)
  634. int x0, y0, dist;
  635. void (*fn) PROTO ((int, int));
  636. {
  637.     int x, y, x1, y1, x2, y2;
  638.  
  639.     dist = min(dist, area.maxdim);
  640.     y1 = y0 - dist;
  641.     y2 = y0 + dist;
  642.     for (y = y1; y <= y2; ++y) {
  643.     if (between(1, y, area.height-2)) {
  644.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  645.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  646.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  647.         for (x = x1; x <= x2; ++x) {
  648.         /* not real efficient, sigh... */
  649.         if (in_area(wrap(x), y)) {
  650.             ((*fn)(wrap(x), y));
  651.         }
  652.         }
  653.     }
  654.     }
  655. }
  656.  
  657. void
  658. apply_to_area_plus_edge(x0, y0, dist, fn)
  659. int x0, y0, dist;
  660. void (*fn) PROTO ((int, int));
  661. {
  662.     int x, y, x1, y1, x2, y2;
  663.  
  664.     dist = min(dist, area.maxdim);
  665.     y1 = y0 - dist;
  666.     y2 = y0 + dist;
  667.     for (y = y1; y <= y2; ++y) {
  668.     if (between(0, y, area.height-1)) {
  669.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  670.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  671.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  672.         for (x = x1; x <= x2; ++x) {
  673.         /* not real efficient, sigh... */
  674.         if (in_area(wrap(x), y)) {
  675.             ((*fn)(wrap(x), y));
  676.         }
  677.         }
  678.     }
  679.     }
  680. }
  681.  
  682. void
  683. apply_to_ring(x0, y0, distmin, distmax, fn)
  684. int x0, y0, distmin, distmax;
  685. void (*fn) PROTO ((int, int));
  686. {
  687.     int dist, x, y, x1, y1, x2, y2;
  688.  
  689.     dist = min(distmax, area.maxdim);
  690.     y1 = y0 - dist;
  691.     y2 = y0 + dist;
  692.     for (y = y1; y <= y2; ++y) {
  693.     if (between(1, y, area.height-2)) {
  694.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  695.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  696.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  697.         for (x = x1; x <= x2; ++x) {
  698.         /* not real efficient, sigh... */
  699.         if (in_area(wrap(x), y) && distance(x, y, x0, y0) >= distmin) {
  700.             ((*fn)(wrap(x), y));
  701.         }
  702.         }
  703.     }
  704.     }
  705. }
  706.  
  707. /* Apply the function to the hexagon bounded by w,h. */
  708.  
  709. void
  710. apply_to_hexagon(x0, y0, w2, h2, fn)
  711. int x0, y0, w2, h2;
  712. void (*fn) PROTO ((int, int));
  713. {
  714.     int x, y, x1, y1, x2, y2;
  715.  
  716.     y1 = limit(y0 - h2);
  717.     y2 = limit(y0 + h2);
  718.     for (y = y1; y <= y2; ++y) {
  719.     if (between(0, y, area.height-1)) {  /* always true? */
  720.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  721.         x1 = x0 - w2 + (y < y0 ? (y0 - y) : 0);
  722.         x2 = x0 + w2 - (y > y0 ? (y - y0) : 0);
  723.         for (x = x1; x <= x2; ++x) {
  724.         /* not real efficient, sigh... */
  725.         if (in_area(wrap(x), y)) {
  726.             ((*fn)(wrap(x), y));
  727.         }
  728.         }
  729.     }
  730.     }
  731. }
  732.  
  733. /* Apply a function all along a path. */
  734.  
  735. void
  736. apply_to_path(fx, fy, tx, ty, dirfn, fn, shortest)
  737. int fx, fy, tx, ty, shortest;
  738. int (*dirfn) PROTO ((int, int, int *, int));
  739. int (*fn) PROTO ((int, int, int, int, int));
  740. {
  741.     int i = 500, j, x = fx, y = fy;
  742.     int dx, dxa, dy, d[NUMDIRS], axis, hextant, tmp, sig;
  743.     int numchoices;
  744.  
  745.     while (!(x == tx && y == ty) && i-- > 0 /* safety */) {
  746.     dx = tx - x;  dy = ty - y;
  747.     /* If in a wrapping world, choose the shortest of directions. */
  748.     if (area.xwrap) {
  749.         dxa = (tx + area.width) - fx;
  750.         if (ABS(dx) > ABS(dxa)) dx = dxa;
  751.         dxa = (tx - area.width) - fx;
  752.         if (ABS(dx) > ABS(dxa)) dx = dxa;
  753.     }
  754.     /* Figure out the axis or hextant of this delta. */
  755.     axis = hextant = -1;
  756.     /* Decode the delta values. */
  757.     if (dx == 0) {
  758.         axis = (dy > 0 ? NORTHEAST : SOUTHWEST);
  759.     } else if (dy == 0) {
  760.         axis = (dx > 0 ? EAST : WEST);
  761.     } else if (dx == (0 - dy)) {
  762.         axis = (dy > 0 ? NORTHWEST : SOUTHEAST);
  763.     } else if (dx > 0) {
  764.         hextant = (dy > 0 ? EAST :
  765.                (ABS(dx) > ABS(dy) ? SOUTHEAST : SOUTHWEST));
  766.     } else {
  767.         hextant = (dy < 0 ? WEST :
  768.                (ABS(dx) > ABS(dy) ? NORTHWEST : NORTHEAST));
  769.     }
  770.     /* On an axis, there's no choice. */
  771.     if (axis >= 0) {
  772.         d[0] = d[1] = axis;
  773.         numchoices = (shortest ? 1 : 3);
  774.     }
  775.     /* Two choices in the middle of a hextant. */
  776.     if (hextant >= 0) {
  777.         d[0] = left_dir(hextant);
  778.         d[1] = hextant;
  779.         numchoices = (shortest ? 2 : 4);
  780.     }
  781.     /* If we don't have to pick a shortest path, we have two more
  782.        directions to try. */
  783.     if (!shortest) {
  784.         d[2] = left_dir(d[0]);
  785.         d[3] = right_dir(d[1]);
  786.     }
  787.     if (dirfn != NULL) {
  788.         if ((numchoices = (*dirfn)(x, y, d, numchoices)) <= 0) return;
  789.     } else {
  790.         /* Be a little random in our choice of directions to try first. */
  791.         if (flip_coin()) {
  792.         tmp = d[0];  d[0] = d[1];  d[1] = tmp;
  793.         tmp = d[2];  d[2] = d[3];  d[3] = tmp;
  794.         }
  795.     }
  796.     /* Try each of the directions. */
  797.     if (!inside_area(x, y)) return;
  798.     for (j = 0; j < numchoices; ++j) {
  799.         sig = (*fn)(x, y, d[j], j, numchoices);
  800.         if (sig > 0) {
  801.         /* It's cool - go with this dir. */
  802.         /* Jump along to the new spot on the path. */
  803.         x += dirx[d[j]];  y += diry[d[j]];
  804.         /* Out of the loop. */
  805.         break;
  806.         } else if (sig < 0) {
  807.         return;
  808.         } else {
  809.         /* Try another. */
  810.         }
  811.     }
  812.     }
  813. }
  814.  
  815. #if 0 /* currently unused */
  816. /* Find a path between the two given points. */
  817.  
  818. /* The chooser function gets passed an small array for directions;
  819.    it is expected to fill it with directions sorted in order of
  820.    preference, and to return the number of directions it found. */
  821.  
  822. /* (the chooser also needs to respect already-marked cells) */
  823. /* (marking should account for all directions in?) */
  824. /* (should return a "figure of merit" sometimes) */
  825. /* (main prog should test vicinity of dest, might not be reachable
  826.    anyway, but maybe should have "reach within n cells") */
  827.  
  828. int
  829. find_path(fx, fy, tx, ty, chooser, maxwps, waypoints, numwpsp)
  830. int fx, fy, tx, ty, maxwps, *numwpsp;
  831. int (*chooser) PROTO ((int, int, int, int, int *));
  832. Waypoint *waypoints;
  833. {
  834.     int ndirs, trythese[NUMDIRS], i;
  835.     int x1, y1, x2, y2;
  836.  
  837.     if (fx == fy && tx == ty) {
  838.     return TRUE;
  839.     }
  840.     ndirs = (*chooser)(x1, y1, x2, y2, trythese);
  841.     if (ndirs == 0) {
  842.     /* We're totally blocked. */
  843.     return FALSE;
  844.     } else {
  845.     for (i = 0; i < ndirs; ++i) {
  846.         /* try this direction with find_path_aux */
  847.     }
  848.     }
  849.     return FALSE;
  850. }
  851. #endif
  852.  
  853. /* Test whether x,y is a valid position anywhere in the current area. */
  854.  
  855. int
  856. in_area(x, y)
  857. int x, y;
  858. {
  859.     return (between(0, y, area.height-1) &&
  860.         (area.xwrap ? TRUE : (between(0, x, area.width-1) &&
  861.                    between(area.height/2+0,
  862.                        x+y,
  863.                        area.width+area.height/2-1))));
  864. }
  865.  
  866. /* This is true if the given x, y position is a valid position for units. */
  867.  
  868. /* Does x testing work right for even/odd heights? */
  869.  
  870. int
  871. inside_area(x, y)
  872. int x, y;
  873. {
  874.     return (between(1, y, area.height-2) &&
  875.         (area.xwrap ? TRUE : (between(1, x, area.width-2) &&
  876.                    between(area.height/2+1,
  877.                        x+y,
  878.                        area.width+area.height/2-2))));
  879. }
  880.  
  881. int
  882. area_cells()
  883. {
  884.     int rslt = area.width * area.height;
  885.  
  886.     if (!area.xwrap) rslt = (rslt * 3) / 4;
  887.     return rslt;
  888. }
  889.         
  890. /* Find the type of the border on the given side of the given hex. */
  891.  
  892. int
  893. border_at(x, y, dir, t)
  894. int x, y, dir, t;
  895. {
  896.     int bord;
  897.  
  898.     if (!inside_area(x, y)
  899.     || !t_is_border(t)
  900.     || !aux_terrain_defined(t))
  901.       return FALSE;
  902.     bord = aux_terrain_at(x, y, t);
  903.     return (bord & (1 << dir));
  904. }
  905.  
  906. /* For now, set a bit on both sides of a border. */
  907.  
  908. void
  909. set_border_at(x, y, dir, t, onoff)
  910. int x, y, dir, t, onoff;
  911. {
  912.     int ox, oy, bord, obord;
  913.     int odir = opposite_dir(dir);
  914.  
  915.     if (!inside_area(x, y) || !t_is_border(t)) return;
  916.     onoff = (onoff ? 1 : 0);  /* make sure it's one bit */
  917.     allocate_area_aux_terrain(t);
  918.     bord = aux_terrain_at(x, y, t);
  919.     bord = ((onoff << dir) | (bord & ~(1 << dir)));
  920.     set_aux_terrain_at(x, y, t, bord);
  921.     /* Go to the other cell and tweak its border bits. */
  922.     point_in_dir(x, y, dir, &ox, &oy);
  923.     obord = aux_terrain_at(ox, oy, t);
  924.     obord = ((onoff << odir) | (obord & ~(1 << odir)));
  925.     set_aux_terrain_at(ox, oy, t, obord);
  926. }
  927.  
  928. /* Find the type of the connection on the given side of the given cell. */
  929.  
  930. int
  931. connection_at(x, y, dir, t)
  932. int x, y, dir, t;
  933. {
  934.     int conn;
  935.  
  936.     if (!inside_area(x, y)
  937.     || !t_is_connection(t)
  938.     || !aux_terrain_defined(t))
  939.       return FALSE;
  940.     conn = aux_terrain_at(x, y, t);
  941.     return (conn & (1 << dir));
  942. }
  943.  
  944. /* For now, set a bit on both sides of a connection. */
  945.  
  946. void
  947. set_connection_at(x, y, dir, t, onoff)
  948. int x, y, dir, t, onoff;
  949. {
  950.     int ox, oy, conn, oconn;
  951.     int odir = opposite_dir(dir);
  952.  
  953.     if (!inside_area(x, y) || !t_is_connection(t)) return;
  954.     allocate_area_aux_terrain(t);
  955.     onoff = (onoff ? 1 : 0);  /* make sure it's one bit */
  956.     conn = aux_terrain_at(x, y, t);
  957.     conn = ((onoff << dir) | (conn & ~(1 << dir)));
  958.     set_aux_terrain_at(x, y, t, conn);
  959.     /* Go to the other cell and tweak its connection bits. */
  960.     point_in_dir(x, y, dir, &ox, &oy);
  961.     oconn = aux_terrain_at(ox, oy, t);
  962.     oconn = ((onoff << odir) | (oconn & ~(1 << odir)));
  963.     set_aux_terrain_at(ox, oy, t, oconn);
  964. }
  965.  
  966. /* If there might be any inconsistencies in borders or connections,
  967.    this fixes them.  Basically this just detects if a bit is set on
  968.    either side, and sets the bits on both sides if so. */
  969.  
  970. void
  971. patch_linear_terrain(t)
  972. int t;
  973. {
  974.     int x, y, dir;
  975.     
  976.     if (t_is_border(t)) {
  977.     for_all_cells(x, y) {
  978.         /* This test is a hack to save some time.  If a cell has no border
  979.            flags in any direction, then either it has no borders or else it
  980.            will be fixed up later on, when an adjacent cell is patched. */
  981.         if (aux_terrain_at(x, y, t) != 0) {
  982.         for_all_directions(dir) {
  983.             if (border_at(x, y, dir, t))
  984.               set_border_at(x, y, dir, t, TRUE);
  985.         }
  986.         }
  987.     }
  988.     } else if (t_is_connection(t)) {
  989.     for_all_cells(x, y) {
  990.         if (aux_terrain_at(x, y, t) != 0) {
  991.         for_all_directions(dir) {
  992.             if (connection_at(x, y, dir, t))
  993.               set_connection_at(x, y, dir, t, TRUE);
  994.         }
  995.         }
  996.     }
  997.     }
  998. }
  999.  
  1000. /* Make space to record named features. */
  1001.  
  1002. void
  1003. init_features()
  1004. {
  1005.     int x, y;
  1006.  
  1007.     featurelist = last_feature = NULL;
  1008.     area.features = malloc_area_layer(short);
  1009.     for_all_cells(x, y) set_raw_feature_at(x, y, 0);
  1010. }
  1011.  
  1012. Feature *
  1013. create_feature(typename, name)
  1014. char *typename, *name;
  1015. {
  1016.     Feature *newfeature = (Feature *) xmalloc(sizeof(Feature));
  1017.  
  1018.     newfeature->id = nextfid++;
  1019.     newfeature->typename = typename;
  1020.     newfeature->name = name;
  1021.     /* Add to the end of the feature list. */
  1022.     if (last_feature != NULL) {
  1023.         last_feature->next = newfeature;
  1024.     } else {
  1025.         featurelist = newfeature;
  1026.     }
  1027.     last_feature = newfeature;
  1028.     return newfeature;
  1029. }
  1030.  
  1031. Feature *
  1032. find_feature(fid)
  1033. int fid;
  1034. {
  1035.     Feature *feature;
  1036.  
  1037.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1038.     if (feature->id == fid) return feature;
  1039.     }
  1040.     return NULL;
  1041. }
  1042.  
  1043. Feature *
  1044. feature_at(x, y)
  1045. int x, y;
  1046. {
  1047.     int fid;
  1048.  
  1049.     if (!features_defined()) return NULL;
  1050.  
  1051.     fid = raw_feature_at(x, y);
  1052.     if (fid == 0) {
  1053.     return NULL;
  1054.     } else {
  1055.     return find_feature(fid);
  1056.     }
  1057. }
  1058.  
  1059. void
  1060. set_feature_type_name(feature, typename)
  1061. Feature *feature;
  1062. char *typename;
  1063. {
  1064.     if (feature == NULL) return;
  1065.     feature->typename = copy_string(typename);
  1066.     /* (should ping all displays) */
  1067. }
  1068.  
  1069. void
  1070. set_feature_name(feature, name)
  1071. Feature *feature;
  1072. char *name;
  1073. {
  1074.     if (feature == NULL) return;
  1075.     feature->name = copy_string(name);
  1076.     /* (should ping all displays) */
  1077. }
  1078.  
  1079. void
  1080. destroy_feature(feature)
  1081. Feature *feature;
  1082. {
  1083.     Feature *tmp, *prev = NULL;
  1084.  
  1085.     if (feature == NULL) return; /* (should be error?) */
  1086.     if (feature == featurelist)
  1087.       featurelist = feature->next;
  1088.     else {
  1089.     for (tmp = featurelist; tmp != NULL; tmp = tmp->next) {
  1090.             if (tmp == feature) {
  1091.         if (prev != NULL)
  1092.           prev->next = tmp->next;
  1093.         break;
  1094.         }
  1095.     }
  1096.     prev = tmp;
  1097.     }
  1098.     /* (should dealloc also?) */
  1099. }
  1100.  
  1101. void
  1102. renumber_features()
  1103. {
  1104.     int newfid = 1, maxoldfid = 0, x, y;
  1105.     short *newlabels;
  1106.     Feature *feature;
  1107.  
  1108.     if (!features_defined()) return;
  1109.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1110.         maxoldfid = max(maxoldfid, feature->id);
  1111.         feature->relabel = newfid++;
  1112.     }
  1113.     if (maxoldfid > 1000) return; /* don't risk it */
  1114.     newlabels = (short *) xmalloc((maxoldfid + 1) * sizeof(short));
  1115.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1116.         newlabels[feature->id] = feature->relabel;
  1117.     }
  1118.     for_all_cells(x, y) {
  1119.         set_raw_feature_at(x, y, newlabels[raw_feature_at(x, y)]);
  1120.     }
  1121.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1122.         feature->id = feature->relabel;
  1123.     }
  1124. }
  1125.  
  1126. void
  1127. compute_all_feature_centroids()
  1128. {
  1129.     int x, y;
  1130.     Feature *feature;
  1131.  
  1132.     /* Only do this if features and a feature layer to work with. */
  1133.     if (featurelist == NULL) return;
  1134.     if (!features_defined()) return;
  1135.     /* Clear out the features. */
  1136.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1137.     feature->size = 0;
  1138.     feature->x = feature->y = 0;
  1139.     }
  1140.     for_all_cells(x, y) {
  1141.     feature = feature_at(x, y);
  1142.     if (feature != NULL) {
  1143.         ++(feature->size);
  1144.         feature->x += x;  feature->y += y;
  1145.     }
  1146.     }
  1147.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1148.     if (feature->size > 0) {
  1149.         feature->x = feature->x / feature->size;
  1150.         feature->y = feature->y / feature->size;
  1151.     }
  1152.     }
  1153. }
  1154.  
  1155. void
  1156. compute_feature_centroid(feature)
  1157. Feature *feature;
  1158. {
  1159.     int x, y, fid;
  1160.  
  1161.     feature->size = 0;
  1162.     feature->x = feature->y = 0;
  1163.     for_all_cells(x, y) {
  1164.     fid = raw_feature_at(x, y);
  1165.     if (feature->id == fid) {
  1166.         feature->x += x;  feature->y += y;
  1167.     }
  1168.     }
  1169.     if (feature->size > 0) {
  1170.     feature->x = feature->x / feature->size;
  1171.     feature->y = feature->y / feature->size;
  1172.     }
  1173. }
  1174.  
  1175. /* Compute the coords of a point in the given direction. */
  1176.  
  1177. int
  1178. point_in_dir(x, y, dir, xp, yp)
  1179. int x, y, dir, *xp, *yp;
  1180. {
  1181.     *xp = wrapx(x + dirx[dir]);  *yp = y + diry[dir];
  1182.     return (in_area(*xp, *yp));
  1183. }
  1184.  
  1185. int
  1186. interior_point_in_dir(x, y, dir, xp, yp)
  1187. int x, y, dir, *xp, *yp;
  1188. {
  1189.     *xp = wrapx(x + dirx[dir]);  *yp = y + diry[dir];
  1190.     return (inside_area(*xp, *yp));
  1191. }
  1192.  
  1193. int
  1194. point_in_dir_n(x, y, dir, n, xp, yp)
  1195. int x, y, dir, n, *xp, *yp;
  1196. {
  1197.     *xp = wrapx(x + n * dirx[dir]);  *yp = y + n * diry[dir];
  1198.     return (in_area(*xp, *yp));
  1199. }
  1200.  
  1201. /* Return a random point guaranteed inside the area. */
  1202.  
  1203. int
  1204. random_point(xp, yp)
  1205. int *xp, *yp;
  1206. {
  1207.     int tries = 500;
  1208.  
  1209.     while (tries-- > 0) {
  1210.     *xp = xrandom(area.width);  *yp = xrandom(area.height - 2) + 1;
  1211.     if (inside_area(*xp, *yp)) return TRUE;
  1212.     }
  1213.     return FALSE;
  1214. }
  1215.  
  1216. /* Return a random point guaranteed to be within a given radius of
  1217.    a given point. */
  1218.  
  1219. int
  1220. random_point_near(cx, cy, radius, xp, yp)
  1221. int cx, cy, radius, *xp, *yp;
  1222. {
  1223.     int tries = 500;
  1224.  
  1225.     if (radius <= 0) return FALSE;
  1226.     while (tries-- > 0) {
  1227.     *xp = cx + xrandom(2 * radius + 1) - radius;
  1228.     *yp = cy + xrandom(2 * radius + 1) - radius;
  1229.     if (inside_area(*xp, *yp)
  1230.         && distance(cx, cy, *xp, *yp) <= radius) return TRUE;
  1231.     }
  1232.     return FALSE;
  1233. }
  1234.  
  1235. /* Return a random point guaranteed to be within a given radius of
  1236.    a given point. */
  1237.  
  1238. int
  1239. random_point_in_area(cx, cy, rx, ry, xp, yp)
  1240. int cx, cy, rx, ry, *xp, *yp;
  1241. {
  1242.     int tries = 500;
  1243.  
  1244.     while (tries-- > 0) {
  1245.     *xp = cx + xrandom(2 * rx + 1) - rx;
  1246.     *yp = cy + xrandom(2 * ry + 1) - ry;
  1247.     if (inside_area(*xp, *yp)
  1248.         && distance(cx, cy, *xp, *yp) <= max(rx - ry, ry - rx))
  1249.       return TRUE;  /* (should fix test?) */
  1250.     }
  1251.     return FALSE;
  1252. }
  1253.  
  1254. /* Generic warning that a terrain subtype is incorrect. */
  1255.  
  1256. void
  1257. terrain_subtype_warning(context, t)
  1258. char *context;
  1259. int t;
  1260. {
  1261.     run_warning("In %s: Garbage t%d (%s) subtype %d",
  1262.         context, t, t_type_name(t), t_subtype(t));
  1263. }
  1264.  
  1265. /* Given a vector, return the direction that best approximates it. */
  1266.  
  1267. int
  1268. approx_dir(dx, dy)
  1269. int dx, dy;
  1270. {
  1271.     if (dx == 0) {
  1272.     if (dy == 0) return -1; /* should flag so can use special cursor */
  1273.     if (dy > 0) return NORTHEAST;
  1274.     return SOUTHWEST;
  1275.     } else if (dx > 0) {
  1276.         /* Check for the axes first. */
  1277.     if (dy == 0) return EAST;
  1278.     if (dy == (-dx)) return SOUTHEAST;
  1279.     if (dy > dx) return NORTHEAST;
  1280.     if ((-dy) <= dx / 2) return EAST;
  1281.     if ((-dy) < dx * 2) return SOUTHEAST;
  1282.     return SOUTHWEST;
  1283.     } else {
  1284.         /* Check for the axes first. */
  1285.     if (dy == 0) return WEST;
  1286.         if (dy == (-dx)) return NORTHWEST;
  1287.     if (dy > (-dx) * 2) return NORTHEAST;
  1288.     if (dy >= (-dx) / 2) return NORTHWEST;
  1289.     if (dy > dx) return WEST;
  1290.     return SOUTHWEST;
  1291.     }
  1292. }
  1293.  
  1294. /* (should flush if really never used) */
  1295.  
  1296. int
  1297. hextant(dx, dy)
  1298. int dx, dy;
  1299. {
  1300.     if (dx < 0) {
  1301.     if (dy < 0) return SOUTHWEST;
  1302.     if (dy == 0) return WEST;
  1303.     return NORTHWEST;
  1304.     } else if (dx == 0) {
  1305.     if (dy > 0) return NORTHEAST;
  1306.     if (dy == 0) return 0; /* should flag so can use special cursor */
  1307.     return SOUTHWEST;
  1308.     } else {
  1309.     if (dy < 0) return SOUTHEAST;
  1310.     if (dy == 0) return EAST;
  1311.     return NORTHEAST;
  1312.     }
  1313. }
  1314.  
  1315. /* Computing distance in a hexagonal system is a little peculiar, since it's
  1316.    sometimes just delta x or y, and other times is the sum.  Basically there
  1317.    are six formulas to compute distance, depending on the direction between
  1318.    the two points.  If the area wraps, this routine reports the shortest
  1319.    distance. */
  1320.  
  1321. int
  1322. distance(x1, y1, x2, y2)
  1323. int x1, y1, x2, y2;
  1324. {
  1325.     int dx = x2 - x1, dy = y2 - y1;
  1326.  
  1327.     if (area.xwrap) {
  1328.         /* Choose the shortest way around a cylinder. */
  1329.         dx = (dx < 0 ? (dx < 0 - area.width / 2 ? area.width + dx : dx)
  1330.                  : (dx > area.width / 2 ? dx - area.width : dx));
  1331.     }
  1332.     if (dx >= 0) {
  1333.     if (dy >= 0) {
  1334.         return (dx + dy);
  1335.     } else if ((0 - dy) <= dx) {
  1336.         return dx;
  1337.     } else {
  1338.         return (0 - dy);
  1339.     }
  1340.     } else {
  1341.     if (dy <= 0) {
  1342.         return (0 - (dx + dy));
  1343.     } else if (dy <= (0 - dx)) {
  1344.         return (0 - dx);
  1345.     } else {
  1346.         return dy;
  1347.     }
  1348.     }
  1349. }
  1350.  
  1351. /* Find the direction matching the given x and y, return -1 if no
  1352.    match.  Callers should be careful to test for this! */
  1353.  
  1354. int
  1355. closest_dir(x, y)
  1356. int x, y;
  1357. {
  1358.     int dir;
  1359.  
  1360.     for_all_directions(dir) {
  1361.     if (dirx[dir] == x && diry[dir] == y) return dir;
  1362.     }
  1363.     return -1;
  1364. }
  1365.  
  1366. /* should put date-handling code here? */
  1367.  
  1368. #ifdef DESIGNERS
  1369.  
  1370. /* Cell painting. */
  1371.  
  1372. static void
  1373. paint_cell_1(x, y)
  1374. int x, y;
  1375. {
  1376.     /* Only do anything if we're actually changing to a different type. */
  1377.     if (terrain_at(x, y) != tmpttype) {
  1378.     set_terrain_at(x, y, tmpttype);
  1379.     see_exact(tmpside, x, y);
  1380.     }
  1381. }
  1382.  
  1383. void
  1384. paint_cell(side, x, y, r, t)
  1385. Side *side;
  1386. int x, y, r, t;
  1387. {
  1388.     tmpside = side;
  1389.     tmpttype = t;
  1390.     apply_to_area_plus_edge(x, y, r, paint_cell_1);
  1391. }
  1392.  
  1393. void
  1394. paint_border(side, x, y, dir, t, mode)
  1395. Side *side;
  1396. int x, y, dir, t, mode;
  1397. {
  1398.     int oldbord;
  1399.  
  1400.     if (!inside_area(x, y)) return;
  1401.     allocate_area_aux_terrain(t);
  1402.     oldbord = border_at(x, y, dir, t);
  1403.     set_border_at(x, y, dir, t, (mode < 0 ? !oldbord : mode));
  1404.     if (oldbord != border_at(x, y, dir, t)) {
  1405.     see_exact(side, x, y);
  1406.     see_exact(side, x+dirx[dir], y+diry[dir]);
  1407.     }
  1408. }
  1409.  
  1410. void
  1411. paint_connection(side, x, y, dir, t, mode)
  1412. Side *side;
  1413. int x, y, dir, t, mode;
  1414. {
  1415.     int oldconn;
  1416.  
  1417.     if (!inside_area(x, y)) return;
  1418.     allocate_area_aux_terrain(t);
  1419.     oldconn = connection_at(x, y, dir, t);
  1420.     set_connection_at(x, y, dir, t, (mode < 0 ? !oldconn : mode));
  1421.     if (oldconn != connection_at(x, y, dir, t)) {
  1422.     see_exact(side, x, y);
  1423.     see_exact(side, x+dirx[dir], y+diry[dir]);
  1424.     }
  1425. }
  1426.  
  1427. /* Coating painting. */
  1428.  
  1429. static void
  1430. paint_coating_1(x, y)
  1431. int x, y;
  1432. {
  1433.     int olddepth = aux_terrain_at(x, y, tmpttype);
  1434.  
  1435.     if (olddepth != tmpint) {
  1436.     set_aux_terrain_at(x, y, tmpttype, tmpint);
  1437.     see_exact(tmpside, x, y);
  1438.     }
  1439. }
  1440.  
  1441. void
  1442. paint_coating(side, x, y, r, t, depth)
  1443. Side *side;
  1444. int x, y, r, t, depth;
  1445. {
  1446.     allocate_area_aux_terrain(t);
  1447.     tmpside = side;
  1448.     tmpttype = t;
  1449.     tmpint = depth;
  1450.     apply_to_area_plus_edge(x, y, r, paint_coating_1);
  1451. }
  1452.  
  1453. /* Painting of people sides. */
  1454.  
  1455. static void
  1456. paint_people_1(x, y)
  1457. int x, y;
  1458. {
  1459.     int oldpeop = people_side_at(x, y);
  1460.  
  1461.     if (oldpeop != tmpint) {
  1462.     set_people_side_at(x, y, tmpint);
  1463.     see_exact(tmpside, x, y);
  1464.     }
  1465. }
  1466.  
  1467. void
  1468. paint_people(side, x, y, r, s)
  1469. Side *side;
  1470. int x, y, r, s;
  1471. {
  1472.     allocate_area_people_sides();
  1473.     tmpside = side;
  1474.     tmpint = s;
  1475.     apply_to_area(x, y, r, paint_people_1);
  1476. }
  1477.  
  1478. /* Painting of geographical features. */
  1479.  
  1480. static void
  1481. paint_feature_1(x, y)
  1482. int x, y;
  1483. {
  1484.     int oldfid = raw_feature_at(x, y);
  1485.     Feature *oldfeature;
  1486.  
  1487.     if (oldfid != tmpint) {
  1488.     set_raw_feature_at(x, y, tmpint);
  1489.     ++(tmpfeature->size);
  1490.     see_exact(tmpside, x, y);
  1491.         if (oldfid != 0) {
  1492.         oldfeature = find_feature(oldfid);
  1493.         if (oldfeature != NULL)
  1494.           --(oldfeature->size);
  1495.     }
  1496.     }
  1497. }
  1498.  
  1499. void
  1500. paint_feature(side, x, y, r, f)
  1501. Side *side;
  1502. int x, y, r, f;
  1503. {
  1504.     Feature *newfeature;
  1505.  
  1506.     if (!features_defined())
  1507.       init_features();
  1508.     newfeature = find_feature(f);
  1509.     if (newfeature != NULL) {
  1510.     tmpside = side;
  1511.     tmpfeature = newfeature;
  1512.     tmpint = f;
  1513.     apply_to_area(x, y, r, paint_feature_1);
  1514.     }
  1515. }
  1516.  
  1517. /* Painting of terrain elevations. */
  1518.  
  1519. static void
  1520. paint_elev_1(x, y)
  1521. int x, y;
  1522. {
  1523.     int n, t = terrain_at(x, y), oldelev = elev_at(x, y);
  1524.  
  1525.     /* Clip desired elevation to what's allowed for the terrain here. */
  1526.     n = max(t_elev_min(t), min(tmpint, t_elev_max(t)));
  1527.     if (n != oldelev) {
  1528.     set_elev_at(x, y, n);
  1529.     see_exact(tmpside, x, y);
  1530.     }
  1531. }
  1532.  
  1533. void
  1534. paint_elevation(side, x, y, r, elev)
  1535. Side *side;
  1536. int x, y, r, elev;
  1537. {
  1538.     allocate_area_elevations();
  1539.     tmpside = side;
  1540.     tmpint = elev;
  1541.     apply_to_area_plus_edge(x, y, r, paint_elev_1);
  1542. }
  1543.  
  1544. static void
  1545. paint_temp_1(x, y)
  1546. int x, y;
  1547. {
  1548.     int n, t = terrain_at(x, y), oldtemp = temperature_at(x, y);
  1549.     
  1550.     n = max(t_temp_min(t), min(tmpint, t_temp_max(t)));
  1551.     if (n != oldtemp) {
  1552.     set_temperature_at(x, y, n);
  1553.     see_exact(tmpside, x, y);
  1554.     }
  1555. }
  1556.  
  1557. void
  1558. paint_temperature(side, x, y, r, temp)
  1559. Side *side;
  1560. int x, y, r, temp;
  1561. {
  1562.     allocate_area_temperatures();
  1563.     tmpside = side;
  1564.     tmpint = temp;
  1565.     apply_to_area_plus_edge(x, y, r, paint_temp_1);
  1566. }
  1567.  
  1568. static void
  1569. paint_material_1(x, y)
  1570. int x, y;
  1571. {
  1572.     int oldm = material_at(x, y, tmpmtype);
  1573.  
  1574.     if (oldm != tmpint) {
  1575.     set_material_at(x, y, tmpmtype, tmpint);
  1576.     see_exact(tmpside, x, y);
  1577.     }
  1578. }
  1579.  
  1580. void
  1581. paint_material(side, x, y, r, m, amt)
  1582. Side *side;
  1583. int x, y, r, m, amt;
  1584. {
  1585.     allocate_area_material(m);
  1586.     tmpside = side;
  1587.     tmpmtype = m;
  1588.     tmpint = amt;
  1589.     apply_to_area_plus_edge(x, y, r, paint_material_1);
  1590. }
  1591.  
  1592. /* Cloud painting is more complicated because up to three separate
  1593.    layers are involved. */
  1594.  
  1595. static void
  1596. paint_clouds_1(x, y)
  1597. int x, y;
  1598. {
  1599.     int oldcl = raw_cloud_at(x, y);
  1600.     int oldbot = raw_cloud_bottom_at(x, y);
  1601.     int oldhgt = raw_cloud_height_at(x, y);
  1602.     int changed = FALSE;
  1603.  
  1604.     if (oldcl != tmpint) {
  1605.     set_raw_cloud_at(x, y, tmpint);
  1606.     changed = TRUE;
  1607.     }
  1608.     if (oldbot != tmpint2) {
  1609.     set_raw_cloud_bottom_at(x, y, tmpint2);
  1610.     changed = TRUE;
  1611.     }
  1612.     if (oldhgt != tmpint3) {
  1613.     set_raw_cloud_height_at(x, y, tmpint3);
  1614.     changed = TRUE;
  1615.     }
  1616.     if (changed) see_exact(tmpside, x, y);
  1617. }
  1618.  
  1619. void
  1620. paint_clouds(side, x, y, r, cloudtype, bot, hgt)
  1621. Side *side;
  1622. int x, y, r, cloudtype, bot, hgt;
  1623. {
  1624.     allocate_area_clouds();
  1625.     /* (should not always do altitudes) */
  1626.     allocate_area_cloud_altitudes();
  1627.     tmpside = side;
  1628.     tmpint = cloudtype;
  1629.     tmpint2 = bot;
  1630.     tmpint3 = hgt;
  1631.     apply_to_area_plus_edge(x, y, r, paint_clouds_1);
  1632. }
  1633.  
  1634. static void
  1635. paint_winds_1(x, y)
  1636. int x, y;
  1637. {
  1638.     int oldw = raw_wind_at(x, y);
  1639.  
  1640.     if (oldw != tmpint) {
  1641.     set_raw_wind_at(x, y, tmpint);
  1642.     see_exact(tmpside, x, y);
  1643.     }
  1644. }
  1645.  
  1646. void
  1647. paint_winds(side, x, y, r, dir, force)
  1648. Side *side;
  1649. int x, y, r, dir, force;
  1650. {
  1651.     allocate_area_winds();
  1652.     tmpside = side;
  1653.     tmpint = force << 3 | dir;
  1654.     apply_to_area_plus_edge(x, y, r, paint_winds_1);
  1655. }
  1656.  
  1657. #endif /* DESIGNERS */
  1658.